package com.ruowei.modules.foodOrder.web.rest;

import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ruowei.common.error.exception.CommonException;
import com.ruowei.common.lang.StringUtils;
import com.ruowei.modules.foodOrder.domain.*;
import com.ruowei.modules.foodOrder.repository.*;
import com.ruowei.modules.foodOrder.web.dto.AddMerchandiseDTO;
import com.ruowei.modules.foodOrder.web.dto.MerchandiseListDTO;
import com.ruowei.modules.foodOrder.web.dto.UpdateMerchandiseDTO;
import com.ruowei.modules.foodOrder.web.dto.UpdateMerchandiseStatusDTO;
import com.ruowei.modules.sys.repository.SysUserRepository;
import com.ruowei.modules.sys.utils.CommonUtils;
import com.ruowei.security.CurrentUser;
import com.ruowei.security.UserModel;
import io.github.jhipster.web.util.PaginationUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import springfox.documentation.annotations.ApiIgnore;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
 * REST controller for managing {@link Merchandise}.
 */
@RestController
@RequestMapping("/api")
@Transactional
@Api(tags = "商品相关")
public class MerchandiseResource {

    private final Logger log = LoggerFactory.getLogger(MerchandiseResource.class);

    private final SysUserRepository sysUserRepository;
    private final MerchandiseRepository merchandiseRepository;
    private final JPAQueryFactory queryFactory;
    private final MerchandiseAttributesRepository attributesRepository;
    private final AttributeOptionsRepository optionsRepository;
    private final MerchandiseSkuRepository skuRepository;
    private final SkuOptionsRelationshipRepository relationshipRepository;

    private final QMerchandise qMerchandise = QMerchandise.merchandise;
    private final QMerchandiseSku qMerchandiseSku = QMerchandiseSku.merchandiseSku;
    private final QSkuOptionsRelationship qSkuOptionsRelationship = QSkuOptionsRelationship.skuOptionsRelationship;
    private final QMerchandiseAttributes qMerchandiseAttributes = QMerchandiseAttributes.merchandiseAttributes;
    private final QAttributeOptions qAttributeOptions = QAttributeOptions.attributeOptions;

    public MerchandiseResource(SysUserRepository sysUserRepository, MerchandiseRepository merchandiseRepository, JPAQueryFactory queryFactory, MerchandiseAttributesRepository attributesRepository, AttributeOptionsRepository optionsRepository, MerchandiseSkuRepository skuRepository, SkuOptionsRelationshipRepository relationshipRepository) {
        this.sysUserRepository = sysUserRepository;
        this.merchandiseRepository = merchandiseRepository;
        this.queryFactory = queryFactory;
        this.attributesRepository = attributesRepository;
        this.optionsRepository = optionsRepository;
        this.skuRepository = skuRepository;
        this.relationshipRepository = relationshipRepository;
    }

    @PostMapping("/createMerchandise")
    @ApiOperation(value = "新增商品")
    public ResponseEntity<Merchandise> createMerchandise(@RequestBody AddMerchandiseDTO dto,
                                                         @ApiIgnore @CurrentUser UserModel userModel) {
        if (merchandiseRepository.existsByMerchantCodeAndTypeCodeAndMerchandiseNameAndDeleteStatus(dto.getMerchantCode(), dto.getTypeCode(), dto.getMerchandiseName(), false)) {
            throw new CommonException("商品已经存在");
        }
        Merchandise merchandise = new Merchandise();
        merchandise.setMerchantCode(dto.getMerchantCode());
        merchandise.setTypeCode(dto.getTypeCode());
        merchandise.setMerchandiseCode(CommonUtils.getUUID());
        merchandise.setMerchandiseName(dto.getMerchandiseName());
        merchandise.setPhotos(dto.getPhotos());
        merchandise.setNewStatus(dto.getNewStatus());
        merchandise.setRecommendStatus(dto.getRecommendStatus());
        merchandise.setDescription(dto.getDescription());
        merchandise.setParticipateFullDiscount(dto.getParticipateFullDiscount());
        merchandise.setSort(dto.getSort());
        merchandise.setSale(0L);
        merchandise.setDeleteStatus(false);
        merchandise.setPublishStatus(false);
        merchandise.setPrice(dto.getPrice());
        merchandiseRepository.save(merchandise);

        new Thread(() -> createDefaultSku(merchandise.getMerchandiseCode(), merchandise.getPrice())).start();
        return ResponseEntity.ok(merchandise);
    }

    private void createDefaultSku(String merchandiseCode, BigDecimal price) {
        Optional<MerchandiseAttributes> attributesOptional =
            attributesRepository.findOneByAttributeNameAndStatusAndMerchandiseCode("默认", true, merchandiseCode);
        MerchandiseAttributes attributes;
        if (!attributesOptional.isPresent()) {
            attributes = new MerchandiseAttributes();
            attributes.setAttributeCode(CommonUtils.getUUID());
            attributes.setAttributeName("默认");
            attributes.setStatus(true);
            attributes.setMerchandiseCode(merchandiseCode);
            attributes.setCreateTime(Instant.now());
            attributesRepository.save(attributes);
        } else {
            attributes = attributesOptional.get();
        }
        Optional<AttributeOptions> optionsOptional =
            optionsRepository.findOneByOptionNameAndAttributeCodeAndStatus("默认", attributes.getAttributeCode(), true);
        AttributeOptions options;
        if (!optionsOptional.isPresent()) {
            options = new AttributeOptions();
            options.setAttributeCode(attributes.getAttributeCode());
            options.setCreateTime(Instant.now());
            options.setOptionCode(CommonUtils.getUUID());
            options.setOptionName("默认");
            options.setStatus(true);
            optionsRepository.save(options);
        } else {
            options = optionsOptional.get();
        }

        MerchandiseSku sku = new MerchandiseSku();
        sku.setUnitPrice(price);
        sku.setSkuCode(CommonUtils.getUUID());
        sku.setAddedTimes(0);
        sku.setStatus(true);
        sku.setMerchandiseCode(merchandiseCode);
        skuRepository.save(sku);

        SkuOptionsRelationship relationship = new SkuOptionsRelationship();
        relationship.setOptionCode(options.getOptionCode());
        relationship.setSkuCode(sku.getSkuCode());
        relationshipRepository.save(relationship);
    }

    @PostMapping("/updateMerchandise")
    @ApiOperation(value = "修改商品")
    public ResponseEntity<Merchandise> updateMerchandise(@RequestBody UpdateMerchandiseDTO dto,
                                                         @ApiIgnore @CurrentUser UserModel userModel) {
        Optional<Merchandise> opt = merchandiseRepository.findOneByMerchandiseCodeAndDeleteStatus(dto.getMerchandiseCode(), false);
        if (!opt.isPresent()) {
            throw new CommonException("该商品不存在");
        }
        Merchandise merchandise = opt.get();
        if (merchandise.isPublishStatus()) {
            throw new CommonException("商品上架时无法修改商品");
        }
        if (StringUtils.isNotEmpty(dto.getMerchandiseName())) {
            merchandise.setMerchandiseName(dto.getMerchandiseName());
        }
        if (dto.getPhotos() != null) {
            merchandise.setPhotos(dto.getPhotos());
        }
        if (dto.getNewStatus() != null) {
            merchandise.setNewStatus(dto.getNewStatus());
        }
        if (dto.getRecommendStatus() != null) {
            merchandise.setRecommendStatus(dto.getRecommendStatus());
        }
        if (StringUtils.isNotEmpty(dto.getDescription())) {
            merchandise.setDescription(dto.getDescription());
        }
        if (dto.getParticipateFullDiscount() != null) {
            merchandise.setParticipateFullDiscount(dto.getParticipateFullDiscount());
        }
        if (null != dto.getSort()) {
            merchandise.setSort(dto.getSort());
        }
        if (StringUtils.isNotEmpty(dto.getTypeCode())) {
            merchandise.setTypeCode(dto.getTypeCode());
        }
        if (dto.getPrice() != null) {
            merchandise.setPrice(dto.getPrice());
        }
        merchandiseRepository.save(merchandise);

        return ResponseEntity.ok(merchandise);
    }


    @PostMapping("/updateMerchandiseStatus")
    @ApiOperation(value = "修改商品状态")
    public ResponseEntity<Merchandise> updateMerchandiseStatus(@RequestBody UpdateMerchandiseStatusDTO dto,
                                                               @ApiIgnore @CurrentUser UserModel userModel) {
        Optional<Merchandise> opt = merchandiseRepository.findOneByMerchandiseCodeAndDeleteStatus(dto.getMerchandiseCode(), false);
        if (!opt.isPresent()) {
            throw new CommonException("该商品不存在");
        }
        Merchandise merchandise = opt.get();
        merchandise.setPublishStatus(dto.getPublishStatus());
        merchandiseRepository.save(merchandise);

        return ResponseEntity.ok(merchandise);
    }


    @GetMapping("/getMerchandiseList")
    @ApiOperation(value = "查询商品列表")
    public ResponseEntity<Page<MerchandiseListDTO>> getMerchandiseList(@RequestParam String typeCode,
                                                                       @ApiIgnore @CurrentUser UserModel userModel,
                                                                       Pageable pageable) {
        JPAQuery<Merchandise> jpaQuery = queryFactory.selectFrom(qMerchandise)
            .where(qMerchandise.typeCode.eq(typeCode)
                .and(qMerchandise.deleteStatus.eq(false)))
            .orderBy(qMerchandise.sort.asc().nullsLast())
            .limit(pageable.getPageSize())
            .offset(pageable.getOffset());
        List<MerchandiseListDTO> result = jpaQuery.fetch().stream().map(merchandise -> {
            List<MerchandiseSku> skus = queryFactory.selectFrom(qMerchandiseSku)
                .where(qMerchandiseSku.status.eq(true)
                    .and(qMerchandiseSku.merchandiseCode.eq(merchandise.getMerchandiseCode())))
                .fetch();
            List<Map<Object, Object>> maps = new ArrayList<>();
            for (MerchandiseSku sku : skus) {
                queryFactory.select(qMerchandiseAttributes.attributeCode, qMerchandiseAttributes.attributeName,
                    qAttributeOptions.optionCode, qAttributeOptions.optionName)
                    .from(qAttributeOptions)
                    .leftJoin(qMerchandiseAttributes).on(qAttributeOptions.attributeCode.eq(qMerchandiseAttributes.attributeCode))
                    .leftJoin(qSkuOptionsRelationship).on(qSkuOptionsRelationship.optionCode.eq(qAttributeOptions.optionCode))
                    .where(qAttributeOptions.status.eq(true)
                        .and(qMerchandiseAttributes.attributeName.ne("默认"))
                        .and(qAttributeOptions.optionName.ne("默认"))
                        .and(qSkuOptionsRelationship.skuCode.eq(sku.getSkuCode()))
                        .and(qMerchandiseAttributes.status.eq(true)))
                    .fetch()
                    .forEach(tuple -> {
                        Map<Object, Object> map = new HashMap<>();
                        map.put("skuCode", sku.getSkuCode());
                        map.put("unitPrice", sku.getUnitPrice());
                        map.put("packingFee", sku.getPackingFee());
                        String attributeName = tuple.get(qMerchandiseAttributes.attributeName);
                        String optionName = tuple.get(qAttributeOptions.optionName);
                        map.put(attributeName, optionName);
                        maps.add(map);
                    });
            }
            MerchandiseListDTO merchandiseListDTO = new MerchandiseListDTO(merchandise);
            merchandiseListDTO.setAttributeOptions(maps);
            return merchandiseListDTO;
        }).collect(Collectors.toList());

        Page<MerchandiseListDTO> page = new PageImpl<>(result, pageable, jpaQuery.fetchCount());
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page);

        return ResponseEntity.ok().headers(headers).body(page);
    }


    @PostMapping("/deleteMerchandise")
    @ApiOperation(value = "删除商品")
    public ResponseEntity<Void> deleteMerchandise(@RequestParam String merchandiseCode,
                                                  @ApiIgnore @CurrentUser UserModel userModel) {
        Optional<Merchandise> opt = merchandiseRepository.findOneByMerchandiseCodeAndDeleteStatus(merchandiseCode, false);
        if (!opt.isPresent()) {
            throw new CommonException("该商品不存在");
        }
        Merchandise merchandise = opt.get();
        merchandise.setDeleteStatus(true);
        merchandiseRepository.save(merchandise);

        return ResponseEntity.ok().build();
    }
}
